# 6. 大数据量表格加载慢的问题解决方案

这篇博客主要是为了总结目前表格加载数据的几种方案以及遇到的问题和解决方法,并不是一个实际的代码实现文。博客思路大概是先介绍下目前SiCAP项目中表格的几种数据加载方案,以及遇到的问题和解决方法。

由于目前表格实现技术是通过vue+elementUI实现的,所以以上解决方法都是通过vue+js+elementUI实现的,不过思路适用于其他技术。

总共有以下几种方案:

  • 一个页面加载所有数据
  • 假分页加载数据(滚动加载数据)
  • 无限分页加载数据
  • 真分页加载数据(滚动加载数据)
  • 模拟滚动实现加载数据

# 一个页面加载所有数据

这个其实就是elementUI自带的table表格功能,一个页面加载所有数据。

这种方案优点就是非常简单啊,直接调用接口获取到数据,然后传入所有数据,最后一行一行全部渲染出来。

但是缺点同样明显,首先要通过后台获取数据,如果数据非常多,那么数据越多接口返回速度就越慢,你就只能看着加载圈圈一直在转啊转。数据返回后还得渲染到页面上,数据量小你可能感觉不到什么,但是数据一旦一多比如一次渲染100条、1000条以上的数据,那么页面就会卡住直到数据渲染到页面上。所以这时就要有新的解决方法了。

# 假分页显示数据(滚动加载数据)

因为后台接口返回数据并不是很慢,但是表格渲染造成页面非常卡。所以这时就需要想一种方法让数据一次不全部渲染完,而是分批渲染。一次只渲染一部分数据,前一次数据渲染完后再渲染新的数据。

这里有两种方案实现。一种就是利用elementUI中的分页器和表格实现,每次只加载当前页面的数据。比如有1000条数据,每页显示100条数据,就会分为10页,第一页显示0-100区间的数据,第二页显示100-200区间的数据,以此类推。通过点击不同页实现数据的截取。另外一种就是不需要分页器,还是在一页显示,只不过首次只加载一部分数据,当鼠标滚动到列表底部的时候再加载其他部分数据,实现思路和假分页其实一样,只不过展示不同,这种情况适用于手机上列表加载上。

这两种方案优点是优化了假数据的渲染速度。

缺点还是没解决后台接口返回数据慢的问题。而且就算分页,一页展示的数据量还是很多、表格复杂的时候还是卡顿。你可能会说一页展示尽可能少的数据,但是如果实际情况是最少展示100条数据,这种方法就不行。

# 无限分页加载数据

由于数据库中数据量增加的非常快,浏览表格时就不能确定总数,否则确定总数后分页器总页数也就固定了。就会造成最后一页的数据有可能显示的不是最新的。比如日志记录统计,这个变化非常快,一会就增加几十条。由于滚动加载的方式可以不用知道总数,就可以使用滚动加载的方式。不过PC端一般都是分页的,所以分页要解决这个问题就必须不确定总数,一直有下一页,可以点击请求后台接口,直到获取没有数据为止。

所以就有了无限分页。实现方式是基于假分页上的。它的思路是先显示前6页的数据,不展示总页数。当点击第6页时再次调用接口返回7-13页数据,以此类推,如果返回的数据量不足6*每页数量则表示目前所有数据已返回了。

这种方案优点是可以在不知道总条数的情况下获取实时部分数据。因为多次请求接口,接口数据返回速度提升。适用于数据量大、数据增加速度快的场景。

缺点是不常用,不好确定数据总数,场景固定。

# 真分页加载数据(滚动加载数据)

由于接口数据返回速度慢,导致表格加载变慢。前面无限分页已经优化了这个问题,但是无限分页不适用于一般的场景。要解决这个问题就必须多次调用接口返回部分数据,而不是一次返回所有数据。

有两种方案解决,一种是真分页,实现方式是基于假分页上的,只不过假分页是在所有数据上截取,而真分页是调用接口实现的。而且还得改动一些勾选全选逻辑,利用缓存记录不同页的勾选情况。它的思路是每次点击分页就给后台发送带当前页参数的请求,请求当前页的数据。另一种就是不需要分页器,还是在一页显示,当鼠标滚动到列表底部的时候再请求其他部分数据,实现思路和真分页其实一样,只不过展示不同,这种情况适用于手机上列表加载上。

优点是接口调用速度提升到最优了。

缺点是一页渲染的数据还是很多、表格复杂的时候还是卡顿。而且代码实现批量操作不同页数据的情况比较复杂。

# 模拟滚动实现加载数据

这种情况和后台接口返回速度没关系,只是为了解决单页面数据量大时的渲染问题。由于某些特定情况导致表格结构复杂、浏览器版本低,导致真分页情况下单页100条数据渲染都消耗很长时间。所以必须想一种方法解决单页可以渲染大量数据而不影响性能。

因为电脑显示屏就那么大,加载表格时你能直观看见的也就最多20条数据左右。所以为什么不可以只渲染20条数据左右,然后鼠标滚动就更新当前数据,DOM数量也就不会增加。就算你有百万条数据,你能直观看见的只能是20条数据左右,你只能通过总条数、滚动条来判断总数。总条数可以通过数据的数量来得到,所以只需要模拟滚动条位置就行了。滚动条一滚动就根据滚动条位置拿到能看见的数据。其实就是通过欺骗用户视觉来达到目的。

你现在有100条数据需要显示在表格中,你直观只能看见20条数据左右,所以你只需要固定表格高度、每行高度就可以知道20行数据的高度,以及其余80条数据的总高度。所以现在加载100条数据的表格可以变成顶部空的只有高度的div和中部你看见的20条数据和底部空的只有高度的div的组合。滚动条向下滚动的时候增加顶部div的高度,减少底部div的高度,改变中部显示的数据。这样就实现了模拟滚动的功能。

优点是优化了表格渲染的性能。可以和假分页真分页一起使用。可以摆脱复杂的分页实现方式,只用单页渲染不卡顿。

缺点是实现起来比较复杂。

# 总结

方式 优点 缺点 适用方向
一个页面加载所有数据 实现、用起来都非常简单 1. 数据多就会造成接口数据返回变慢。
2. 页面渲染卡顿
1. 表格结构简单
2. 数据少量
假分页显示数据(滚动加载数据) 相比全部渲染,渲染速度提升了很多 1. 数据多就会造成接口数据返回变慢。
2. 页面渲染有可能还是卡顿
1. 滚动适用于手机端。
2. 表格结构简单,每页行尽可能地少
无限分页加载数据 1. 可以实时显示数据。
2. 数据返回速度提升
1. 场景少不常用。
2. 不好确定数据总数。
3. 代码不好实现
适用于数据增加速度快的情况
真分页加载数据(滚动加载数据) 数据返回速度提升到最优 1. 页面渲染有可能还是卡顿。
2. 代码实现其他逻辑难,比如记录不同页的勾选
1. 滚动适用于手机端。
2. 表格结构简单,每页行尽可能地少
模拟滚动实现加载数据 优化了浏览器渲染列表性能 1. 代码实现起来比较复杂。 1. 可以在假分页、真分页中使用。
2. 可以单页实现大数据渲染